#include <stdio.h>
#include <stdlib.h>

// 循环队列是为了解决正常队列入队时，如果队头前面有位置，需要挪动数据的问题。
// 数据量小的时候，挪动还能接受，数据量大了，挪动起来就很麻烦。
// 如果把队列首位相接，做循环队列，就不需要往前挪动了。

#define MAX_SIZE 100
typedef int ElementType; // 元素类型

//队列结构体
typedef struct Queue{
    ElementType* data; //数据域
    int front; //头指针
    int rear; //尾指针
}Queue;

//初始化队列
Queue* InitQueue(){
    Queue* q = (Queue*)malloc(sizeof(Queue));
    q->data = (ElementType*)malloc(MAX_SIZE * sizeof(ElementType));
    q->front = 0;
    q->rear = 0;
    return q;
}

//入队
int equeue(Queue* q, ElementType e){
    if ((q->rear + 1) % MAX_SIZE == q->front){ // 假设队列长度为8，队尾下标也就是rear=7时,(7+1)%8=0
        printf("队列已满。\n");
        return 0;
    }
    q->data[q->rear] = e;
    printf("当前入队元素：%d\n",e);
    q->rear = (q->rear + 1) % MAX_SIZE; 
    // 细品，假设MAX_SIZE=8，rear从0开始。则队尾指针q->rear
    // 会一直从0~7里循环，代入公式算算就知道了。
    return 1;
}

//出队
/*
队列所谓的出队，和出栈，顺序表删除元素等等差不多，不是真的删除元素
而是用变量记录被删除数据，然后挪动指针，减少队列长度
*/
int dequeue(Queue *q, ElementType *e){
    if(q->front == q->rear)
    {
        printf("空队列");
        return 0;
    }
    *e = q->data[q->front];
    printf("当前出队元素：%d\n",*e);
    q->front = (q->front + 1) % MAX_SIZE;
    return 1;
}

// 获取队头元素
int getHead(Queue *q,ElementType *e){
    if(q->front == q->rear)
    {
        printf("空队列");
        return 0;
    }
    *e = q->data[q->front];
    printf("当前队头元素：%d\n",*e);
    return *e;
}

int main(){
    Queue *q = InitQueue();
    equeue(q,10);
    equeue(q,20);
    equeue(q,30);
    int a;
    getHead(q,&a);
    dequeue(q,&a);
    return 0;
}